package upm.pb4agent.team3;

import jade.content.Concept;
import jade.content.ContentElement;
import jade.content.lang.Codec;
import jade.content.lang.sl.SLCodec;
import jade.content.onto.Ontology;
import jade.content.onto.basic.Action;
import jade.core.AID;
import jade.core.Agent;
import jade.core.behaviours.SimpleBehaviour;
import jade.lang.acl.ACLMessage;
import jade.lang.acl.MessageTemplate;
import jade.util.leap.ArrayList;
import jade.util.leap.Iterator;
import jade.util.leap.List;
import jade.wrapper.AgentContainer;
import jade.wrapper.AgentController;

import java.util.Date;

import upm.pb4agent.ontology.Dock;
import upm.pb4agent.ontology.DockDesignation;
import upm.pb4agent.ontology.PB4AgentOntology;
import upm.pb4agent.ontology.Registration;
import upm.pb4agent.ontology.RegistrationForm;


/**
 * This agent has the following functionality: 
 * <ul>
 * <li> 
 * <li> 
 * </ul>
 * @author Team3, UPM
 */
public class RegistrationDesk extends Agent {

	private static final long serialVersionUID = 6110888192554850312L;
	
	public Codec codec = new SLCodec();
	public Ontology ontology = PB4AgentOntology.getInstance();
	
	//private AID agWatcherAid = null;
	private AID agRefereeAid = null;
	
	private boolean isRegistrationClosed = false;
	private boolean isntNotifyRaceStart = true;
	//private boolean isntNotifyWatcherRegistrationClosed = true;
	
	private long registrationPeriodProp;	
	private Long registrationTime;
	

	protected void setup() {

		System.out.println(getLocalName() + ": enters the system");

		getContentManager().registerLanguage(codec);
		getContentManager().registerOntology(ontology);

		MyAgent.registerAgentInDF(this,Constant.SD_REGISTRATION_DESK);
		
		//agWatcherAid = MyAgent.searchAgentInDF(this,Constant.SD_WATCHER);
		agRefereeAid = MyAgent.searchAgentInDF(this,Constant.SD_REFEREE);
		
		ReadConfiguration.getInstance(0);
		String registrationPeriodStr = ReadConfiguration.getValue("registration_period");		
		registrationPeriodProp = Long.valueOf(registrationPeriodStr);
		
		registrationTime = new Date().getTime();
		addBehaviour(new ProcessRegistrationFromManager(this));
	}
	
	

	class ProcessRegistrationFromManager extends SimpleBehaviour {
		private static final long serialVersionUID = -5444735014847500036L;
		Agent myAgent = null;
		public ProcessRegistrationFromManager(Agent agent) {			
			super(agent);
			myAgent = agent;			
		}
		
		public void action() {
			Long currentTime = new Date().getTime();
			String teamID = "";
			
			ACLMessage aclMessage = receive( MessageTemplate.and(
																    MessageTemplate.and(			
																		   				 MessageTemplate.MatchLanguage(codec.getName())
																		   				,MessageTemplate.MatchOntology(ontology.getName())
																		   			   )
																	,MessageTemplate.MatchProtocol("Registration")
																	)
											);					
						
			
			
			
			
			if((currentTime - registrationTime) < registrationPeriodProp){//If the registration period is open
				if(aclMessage != null){// No message yet				
					ACLMessage reply = aclMessage.createReply();					
					// Wait for a registration request
					if(aclMessage.getPerformative() == ACLMessage.REQUEST){//&& aclMessage.getProtocol().equals("Registration")) {
						// Processing request
						ContentElement contentElement = null;
						try{
							contentElement = getContentManager().extractContent(aclMessage);
							
							if(contentElement instanceof Action) {
								Action action = (Action) contentElement;
								Concept concept = action.getAction();
								if(concept instanceof Registration) {
									Registration registration = (Registration) concept;
									teamID = registration.getRegistrationForm().getTeamID().getValue();
									// Validate the registration form						
									if(validateRegistrationForm(registration.getRegistrationForm())) {
										//Inform the sender
										reply.setPerformative(ACLMessage.INFORM);
										myAgent.send(reply);
										System.out.println(getLocalName() + ": '" + teamID + "' is accepted");									
										
										AID agWatcherAid = createAgentWatcherForTeamX(Constant.NAME_WATCHER_X + teamID);
										
										if(agWatcherAid != null){
											Action actionWatchBoat = new Action(agWatcherAid,registration);
											
											ACLMessage aclMessageToWatcher = new ACLMessage(ACLMessage.INFORM);
											aclMessageToWatcher.setLanguage(codec.getName());
											aclMessageToWatcher.setOntology(ontology.getName());
											aclMessageToWatcher.addReceiver(agWatcherAid);
											aclMessageToWatcher.setProtocol("MakeBoat");
											
											getContentManager().fillContent(aclMessageToWatcher, actionWatchBoat);
											send(aclMessageToWatcher);
						
											System.out.println(getLocalName() + ": INFORM: 'MakeBoat' for team: '" +  teamID + "'  --> "+ agWatcherAid.getLocalName());
										}
										//Fin: enviando to watcher																			
									}else{//if(isRegistrationFormValid == false)
										//Refuse the request
										reply.setPerformative(ACLMessage.REFUSE);
										myAgent.send(reply);
										System.out.println(getLocalName() + ": " + teamID + " is disqualified Invalid RegistrationForm");
									}
								}
							}
						}catch(Exception e){
							System.out.println(Constant.NAME_REGISTRATION_DESK + ", error: " + e.toString());
						}
					}else{//Message format is wrong
						reply.setPerformative(ACLMessage.NOT_UNDERSTOOD);
						myAgent.send(reply);
						System.out.println(getLocalName() +  ": " + teamID + " msg not understood");
					}					
				}else{
					isRegistrationClosed = false;
				}
			}else{//If the registration period is close				
				if(isntNotifyRaceStart){
					if(agRefereeAid == null){
						agRefereeAid = MyAgent.searchAgentInDF(super.myAgent,Constant.SD_REFEREE);
					}else{
						ACLMessage msg = new ACLMessage(ACLMessage.INFORM);
						msg.addReceiver(agRefereeAid);
						msg.setProtocol("NotifyRaceStart");
						msg.setContent("NotifyRaceStart");
						msg.setLanguage(codec.getName());
						msg.setOntology(ontology.getName());
						
						send(msg);
						//isntNotifyRaceStart = false;
						isRegistrationClosed = true;
						System.out.println(getLocalName() +  ": Registration Period is Over. --> Referee");
					}
				}
				
				
				/*if(isntNotifyWatcherRegistrationClosed){
					if(agWatcherAid == null){
						//agWatcherAid = MyAgent.searchAgentInDF(super.myAgent,Constant.SD_WATCHER);
					//}else{					
						ACLMessage msg= new ACLMessage(ACLMessage.INFORM);					
						msg.addReceiver(agWatcherAid);
						msg.setLanguage(codec.getName());
						msg.setOntology(ontology.getName());
						msg.setProtocol("RegistrationClosed");
						send(msg);
						isntNotifyWatcherRegistrationClosed = false;
						System.out.println(getLocalName() +  ": Registration Period is Over. --> Watcher");
					}
				}*/
				
				/*if(!(isntNotifyRaceStart && isntNotifyWatcherRegistrationClosed)){
					isRegistrationClosed = true;//ambos notificados
				}*/
			}

		}
		public boolean done() {
			return isRegistrationClosed;
		}
		
		
		private boolean validateRegistrationForm(RegistrationForm registrationForm) {

			// Variable declaration
			List dockDesignationList = registrationForm.getDockDesignation();
			boolean isValid = true;
			List rowerIDList = new ArrayList();
			List dockNameList = new ArrayList();
			AID rowerID = null;
			Dock dock = null;
			Iterator iterator = dockDesignationList.iterator();
			String teamID = registrationForm.getTeamID().getValue();

			if (dockDesignationList.size()!=Constant.MAX_NUMBER_OF_ROWERS){
				isValid = false;
				//System.out.println(getLocalName() + ": " + teamID + " wrong number of rowers: " + dockDesignationList.size());
			}else{
				while (iterator.hasNext() == true) {
					DockDesignation dockDesignation = (DockDesignation) iterator.next();
					rowerID = dockDesignation.getRowerID();
					dock = dockDesignation.getDock();

					// Check if the ID is already in the list
					if (rowerIDList.contains(rowerID) == true) {
						isValid = false;
						break;
					} else {
						rowerIDList.add(rowerID);
					}

					// Check if the dock is already in the list
					if (dockNameList.contains(dock.getName()) == true) {
						isValid = false;
						break;
					} else {
						dockNameList.add(dock.getName());
					}
				}
				//System.out.println(getLocalName() + ": " + teamID + " number of members: " + rowerIDList.size());
			}

			return isValid;
		}
	}
	
	public AID createAgentWatcherForTeamX(String watcherName) {
		try{
			AgentContainer agentContainer = getContainerController();
			
			AgentController agentController = agentContainer.createNewAgent(   watcherName
																			 , Constant.CLASS_WATCHER
																			 , null);			
			
			agentController.start();				
			
			return new AID(watcherName, AID.ISLOCALNAME);
		}catch(Exception e){
			System.out.println(Constant.NAME_REGISTRATION_DESK + ".createAgentWatcherForTeamX() -::- error: " + e.toString());
			return null;
		}
	}
	
}